package sdf

import (
	"BlendSDF/sdf/init_matrix"
	"math"
	"sync"
)

var wg sync.WaitGroup

func GenerateSDF(length, width int, m [][]*init_matrix.Point, masks [][]bool) (res [][]float64) {
	res = make([][]float64, width)
	//1st pass
	for i := 0; i < width; i++ {
		//left to right
		for j := 0; j < length; j++ {
			computeShortestDistance(m, masks, i, j, length, width)
		}
		//right to left
		for j := length - 1; j > -1; j-- {
			computeShortestDistance(m, masks, i, j, length, width)
		}
	}
	//2nd pass
	for j := 0; j < length; j++ {
		//top to bottom
		for i := 0; i < width; i++ {
			computeShortestDistance(m, masks, i, j, length, width)
		}
		//bottom to top
		for i := width - 1; i > -1; i-- {
			computeShortestDistance(m, masks, i, j, length, width)
		}
	}
	for i := 0; i < width; i++ {
		wg.Add(1)
		go func(i int) {
			defer wg.Done()
			temp := make([]float64, length)
			for j := 0; j < length; j++ {
				temp[j] = math.Sqrt(m[i][j].DistanceSqu(0, 0))
				//设置有向距离
				if !masks[i][j] {
					temp[j] *= -1
				}
			}
			res[i] = temp
		}(i)
	}
	wg.Wait()
	return
}

func computeShortestDistance(m [][]*init_matrix.Point, masks [][]bool, i, j, length, width int) {
	var _min = math.Inf(1)
	//变化信号
	var ok bool
	for x := i - 1; x <= i+1; x++ {
		for y := j - 1; y <= j+1; y++ {
			if i == x && j == y {
				continue
			}
			//存在
			if isEsist(x, y, length, width) {
				//距离场不为0且遮罩相同
				if m[x][y].DistanceSqu(0, 0) != 0 && masks[i][j] == masks[x][y] {
					_min, ok = Min(_min, m[x][y].DistanceSqu(math.Abs(float64(x-i)), math.Abs(float64(y-j))))
				} else if masks[i][j] != masks[x][y] {
					//遮罩不相同，说明位于边界
					_min, ok = Min(_min, math.Pow(math.Abs(float64(x-i))/2, 2)+math.Pow(math.Abs(float64(y-j))/2, 2))
				} else {
					//其余情况为false
					ok = false
				}
				//最小值发生变化时
				if ok {
					if masks[x][y] == masks[i][j] {
						//距离场扩散
						m[i][j].DX = m[x][y].DX + math.Abs(float64(x-i))
						m[i][j].DY = m[x][y].DY + math.Abs(float64(y-j))
					} else if masks[x][y] != masks[i][j] {
						//设置边界sdf
						if !masks[i][j] {
							//位于符号内部时
							m[i][j].DX = -math.Abs(float64(x-i)) / 2
							m[i][j].DY = -math.Abs(float64(y-j)) / 2
						} else {
							//位于符号外部时
							m[i][j].DX = math.Abs(float64(x-i)) / 2
							m[i][j].DY = math.Abs(float64(y-j)) / 2
						}
					}
				}
			}
		}
	}
}

// 检测元素是否存在
func isEsist(i, j, length, width int) bool {
	if i < 0 || j < 0 {
		return false
	} else if i >= width || j >= length {
		return false
	}
	return true
}

func Min(_min, num float64) (float64, bool) {
	if num < _min {
		return num, true
	}
	return _min, false
}
